```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Kafka消费延迟问题深度解析 | 技术小馆</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            color: #333;
            line-height: 1.6;
        }
        h1, h2, h3, h4, h5, h6 {
            font-family: 'Noto Serif SC', serif;
            font-weight: 600;
            margin-top: 1.5em;
            margin-bottom: 0.5em;
        }
        .hero-gradient {
            background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 50%, #a855f7 100%);
        }
        .code-block {
            background-color: #2d3748;
            border-radius: 0.5rem;
            padding: 1rem;
            position: relative;
        }
        .code-header {
            background-color: #1a202c;
            color: #e2e8f0;
            padding: 0.5rem 1rem;
            border-top-left-radius: 0.5rem;
            border-top-right-radius: 0.5rem;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .code-content {
            color: #f8fafc;
            overflow-x: auto;
            padding: 1rem 0;
        }
        .highlight {
            background-color: rgba(124, 58, 237, 0.1);
            padding: 0.2rem 0.4rem;
            border-radius: 0.25rem;
            font-weight: 500;
        }
        .card-hover {
            transition: all 0.3s ease;
        }
        .card-hover:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
        }
        .divider {
            height: 1px;
            background: linear-gradient(90deg, rgba(124, 58, 237, 0) 0%, rgba(124, 58, 237, 0.5) 50%, rgba(124, 58, 237, 0) 100%);
            margin: 2rem 0;
        }
        .fact-box {
            border-left: 4px solid #7c3aed;
            padding-left: 1rem;
            margin: 1.5rem 0;
        }
    </style>
</head>
<body class="bg-gray-50">
    <!-- Hero Section -->
    <section class="hero-gradient text-white py-20 px-4 md:px-0">
        <div class="container mx-auto max-w-5xl text-center">
            <div class="inline-block bg-indigo-700 text-xs font-semibold px-3 py-1 rounded-full mb-4">
                <i class="fas fa-bolt mr-2"></i>分布式系统专题
            </div>
            <h1 class="text-4xl md:text-5xl font-bold leading-tight mb-6">
                Kafka消费延迟问题
                <br>
                <span class="text-indigo-200">深度解析与优化策略</span>
            </h1>
            <p class="text-xl text-indigo-100 max-w-3xl mx-auto mb-10">
                探索高吞吐量消息系统中延迟问题的根源，从消费者拉取机制到Broker负载优化，全面剖析Kafka消费延迟的解决方案。
            </p>
            <div class="flex justify-center space-x-4">
                <a href="#reasons" class="bg-white text-indigo-600 hover:bg-indigo-50 px-6 py-3 rounded-full font-medium transition duration-300">
                    <i class="fas fa-search mr-2"></i>问题原因
                </a>
                <a href="#solutions" class="bg-indigo-800 hover:bg-indigo-700 text-white px-6 py-3 rounded-full font-medium transition duration-300">
                    <i class="fas fa-lightbulb mr-2"></i>优化方案
                </a>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="container mx-auto max-w-5xl px-4 py-12">
        <!-- Intro Section -->
        <section class="mb-16">
            <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
                <div class="p-8">
                    <h2 class="text-2xl font-bold text-gray-800 mb-4">Kafka消费延迟概述</h2>
                    <p class="text-gray-600 mb-6">
                        Kafka 作为一个高吞吐量、低延迟的分布式消息队列，常被用来做实时数据传输和日志处理。然而，在实际的生产环境中，Kafka 的消费者可能会出现消费延迟的问题。消费延迟主要指的是消息从 Kafka 集群中被消费的时间滞后于生产者写入消息的时间。
                    </p>
                    <div class="fact-box">
                        <p class="text-gray-700 font-medium">
                            <i class="fas fa-exclamation-circle text-indigo-500 mr-2"></i>
                            影响消费延迟的因素有很多，包括消费者的配置、Kafka 集群的健康状况、消费者的处理能力等。
                        </p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Data Visualization -->
        <section class="mb-16">
            <h2 id="reasons" class="text-3xl font-bold text-gray-800 mb-8 flex items-center">
                <i class="fas fa-project-diagram text-indigo-500 mr-3"></i>
                消费延迟的核心因素
            </h2>
            <div class="bg-white rounded-xl shadow-md p-6 mb-8">
                <div class="mermaid">
                    graph TD
                        A[Kafka消费延迟] --> B[消费者拉取延迟]
                        A --> C[消息处理延迟]
                        A --> D[Broker负载]
                        A --> E[消息积压]
                        B --> B1[网络延迟]
                        B --> B2[拉取频率]
                        B --> B3[批量拉取]
                        C --> C1[业务逻辑复杂度]
                        C --> C2[处理能力]
                        C --> C3[外部依赖]
                        D --> D1[磁盘I/O]
                        D --> D2[副本同步]
                        E --> E1[消费速度]
                        E --> E2[生产速度]
                </div>
            </div>
        </section>

        <!-- Reasons Section -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold text-gray-800 mb-8">1. 消费延迟的产生原因</h2>
            <p class="text-gray-600 mb-6">
                消费延迟的根本原因在于消息从生产者到消费者的处理过程中，可能会遇到以下几个因素：
            </p>
            
            <div class="grid md:grid-cols-2 gap-6 mb-8">
                <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
                    <div class="p-6">
                        <div class="flex items-center mb-4">
                            <div class="bg-indigo-100 text-indigo-600 p-3 rounded-full mr-4">
                                <i class="fas fa-network-wired text-xl"></i>
                            </div>
                            <h3 class="text-xl font-semibold text-gray-800">消费者拉取消息的延迟</h3>
                        </div>
                        <p class="text-gray-600">
                            消费者从 Kafka Broker 拉取消息时可能存在网络延迟、拉取频率、批量拉取等因素的影响。
                        </p>
                    </div>
                </div>
                
                <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
                    <div class="p-6">
                        <div class="flex items-center mb-4">
                            <div class="bg-purple-100 text-purple-600 p-3 rounded-full mr-4">
                                <i class="fas fa-cogs text-xl"></i>
                            </div>
                            <h3 class="text-xl font-semibold text-gray-800">消息处理的延迟</h3>
                        </div>
                        <p class="text-gray-600">
                            消费者在处理消息时的业务逻辑可能导致延迟，特别是在高负载或计算密集型的情况下。
                        </p>
                    </div>
                </div>
                
                <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
                    <div class="p-6">
                        <div class="flex items-center mb-4">
                            <div class="bg-blue-100 text-blue-600 p-3 rounded-full mr-4">
                                <i class="fas fa-server text-xl"></i>
                            </div>
                            <h3 class="text-xl font-semibold text-gray-800">Kafka Broker 的负载</h3>
                        </div>
                        <p class="text-gray-600">
                            Kafka Broker 需要从磁盘中读取消息，并进行网络传输。如果 Broker 负载较高，也可能导致消息消费延迟。
                        </p>
                    </div>
                </div>
                
                <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
                    <div class="p-6">
                        <div class="flex items-center mb-4">
                            <div class="bg-red-100 text-red-600 p-3 rounded-full mr-4">
                                <i class="fas fa-tasks text-xl"></i>
                            </div>
                            <h3 class="text-xl font-semibold text-gray-800">消息积压</h3>
                        </div>
                        <p class="text-gray-600">
                            当消费者无法及时消费消息时，会导致消息在 Kafka 中积压，进一步增加消费延迟。
                        </p>
                    </div>
                </div>
            </div>
        </section>

        <div class="divider"></div>

        <!-- Pull Mechanism Section -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold text-gray-800 mb-8">2. Kafka 消费者端的拉取机制</h2>
            <p class="text-gray-600 mb-6">
                消费者端的拉取机制（Poll）是 Kafka 消费延迟的重要一环。在 Kafka 中，消费者通过调用 <span class="highlight">poll</span> 方法拉取消息。
            </p>
            
            <div class="mb-8">
                <div class="code-block">
                    <div class="code-header">
                        <span>KafkaConsumer.java - poll方法核心逻辑</span>
                        <span class="text-xs">Java</span>
                    </div>
                    <div class="code-content">
                        <pre><code>public ConsumerRecords&lt;K, V&gt; poll(long timeout) {
    // 1. 获取拉取的消息
    List&lt;ConsumerRecord&lt;K, V&gt;&gt; records = fetchRecords(timeout);
    
    // 2. 消息处理前的准备工作
    long pollEndTime = time.milliseconds();
    for (ConsumerRecord&lt;K, V&gt; record : records) {
        // 消息处理
        processRecord(record);
    }
    
    return new ConsumerRecords&lt;&gt;(records);
}</code></pre>
                    </div>
                </div>
            </div>
            
            <h3 class="text-2xl font-semibold text-gray-800 mb-4">拉取消息的具体流程：</h3>
            <ol class="list-decimal list-inside text-gray-600 space-y-3 mb-6">
                <li><span class="font-medium">调用 fetchRecords：</span>消费者首先会向 Kafka Broker 请求消息，这个请求会返回指定分区的消息。</li>
                <li><span class="font-medium">发送 Fetch 请求：</span>通过 sendFetchRequest 方法，消费者会向 Kafka Broker 发送请求。</li>
                <li><span class="font-medium">解析响应消息：</span>返回的消息会经过解码，转化为 ConsumerRecord 对象，供后续处理。</li>
            </ol>
            
            <div class="bg-blue-50 border border-blue-100 rounded-lg p-6 mb-8">
                <h4 class="text-lg font-semibold text-blue-800 mb-3 flex items-center">
                    <i class="fas fa-info-circle mr-2"></i>拉取延迟的可能原因
                </h4>
                <ul class="text-blue-700 space-y-2">
                    <li class="flex items-start">
                        <i class="fas fa-network-wired text-blue-500 mr-2 mt-1"></i>
                        <span><span class="font-medium">网络延迟：</span>网络环境不稳定或带宽限制可能导致拉取请求的延迟。</span>
                    </li>
                    <li class="flex items-start">
                        <i class="fas fa-server text-blue-500 mr-2 mt-1"></i>
                        <span><span class="font-medium">Broker 负载高：</span>当 Kafka Broker 承载过多消费者请求或负载过重时，响应的时间可能会增加。</span>
                    </li>
                </ul>
            </div>
            
            <div class="code-block mb-8">
                <div class="code-header">
                    <span>KafkaConsumer.java - fetchRecords方法实现</span>
                    <span class="text-xs">Java</span>
                </div>
                <div class="code-content">
                    <pre><code>private List&lt;ConsumerRecord&lt;K, V&gt;&gt; fetchRecords(long timeout) {
    // 发送 Fetch 请求到 Kafka Broker
    FetchRequest fetchRequest = createFetchRequest(timeout);
    FetchResponse fetchResponse = sendFetchRequest(fetchRequest);
    // 解析返回的消息
    List&lt;ConsumerRecord&lt;K, V&gt;&gt; records = parseFetchResponse(fetchResponse);
    return records;
}</code></pre>
                </div>
            </div>
        </section>

        <div class="divider"></div>

        <!-- Message Processing Section -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold text-gray-800 mb-8">3. Kafka 消费者的消息处理</h2>
            <p class="text-gray-600 mb-6">
                消费者端收到消息后，需要进行一系列的业务处理。在此过程中，消费者的处理能力、业务逻辑以及其他系统因素都可能导致消费延迟。
            </p>
            
            <div class="code-block mb-8">
                <div class="code-header">
                    <span>KafkaConsumer.java - 消息处理逻辑</span>
                    <span class="text-xs">Java</span>
                </div>
                <div class="code-content">
                    <pre><code>private void processRecord(ConsumerRecord&lt;K, V&gt; record) {
    try {
        // 1. 处理消息的业务逻辑
        processBusinessLogic(record);
    } catch (Exception e) {
        // 2. 异常处理
        handleException(e);
    }
}</code></pre>
                </div>
            </div>
            
            <div class="grid md:grid-cols-3 gap-6 mb-8">
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center">
                        <i class="fas fa-code-branch text-indigo-500 mr-2"></i>
                        业务逻辑的复杂性
                    </h3>
                    <p class="text-gray-600">
                        如果消费者的业务逻辑复杂，比如需要进行大量的数据计算或依赖其他系统（如数据库、外部服务等），可能导致延迟。
                    </p>
                </div>
                
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center">
                        <i class="fas fa-boxes text-purple-500 mr-2"></i>
                        批量处理
                    </h3>
                    <p class="text-gray-600">
                        Kafka 支持批量消息处理，如果消费者一次性处理大量消息，可能会增加延迟。
                    </p>
                </div>
                
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3 flex items-center">
                        <i class="fas fa-users-cog text-blue-500 mr-2"></i>
                        消费者并发
                    </h3>
                    <p class="text-gray-600">
                        Kafka 消费者的并发处理能力也是影响延迟的因素之一。消费者可以通过多线程或异步机制提高处理能力。
                    </p>
                </div>
            </div>
        </section>

        <div class="divider"></div>

        <!-- Poll Frequency Section -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold text-gray-800 mb-8">4. 消费者拉取消息的频率</h2>
            <p class="text-gray-600 mb-6">
                Kafka 消费者通常是定时拉取消息，拉取的频率直接影响到消费延迟。在高频拉取的情况下，消费者会尽可能快地消费消息，减少延迟。若消费者的拉取频率较低，可能会导致消息积压，增加消费延迟。
            </p>
            
            <div class="code-block mb-6">
                <div class="code-header">
                    <span>Consumer.java - poll频率控制</span>
                    <span class="text-xs">Java</span>
                </div>
                <div class="code-content">
                    <pre><code>// Consumer.java
public void pollOnce() {
    // 定时调用 poll 方法，间隔时间由配置决定
    ConsumerRecords&lt;K, V&gt; records = poll(pollTimeoutMs);
}</code></pre>
                </div>
            </div>
            
            <div class="grid md:grid-cols-3 gap-6">
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3">
                        max.poll.interval.ms
                    </h3>
                    <p class="text-gray-600">
                        控制消费者最大拉取间隔。如果消费者的消息处理时间过长，超出了该时间，消费者会被认为没有及时响应，从而被重平衡。
                    </p>
                </div>
                
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3">
                        fetch.min.bytes
                    </h3>
                    <p class="text-gray-600">
                        决定消费者每次拉取消息的最小字节数。如果设置过高，可能会导致消费延迟。
                    </p>
                </div>
                
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3">
                        fetch.max.wait.ms
                    </h3>
                    <p class="text-gray-600">
                        控制消费者等待消息的最大时间。需要与fetch.min.bytes配合使用，影响消费者的响应速度。
                    </p>
                </div>
            </div>
        </section>

        <div class="divider"></div>

        <!-- Auto Commit Section -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold text-gray-800 mb-8">5. 消费者的自动提交机制</h2>
            <p class="text-gray-600 mb-6">
                Kafka 提供了消费者的自动提交机制，用于定期提交消费者的位移（offset）。位移提交的延迟可能影响消费者的消费进度，进而引发消费延迟。
            </p>
            
            <div class="code-block mb-6">
                <div class="code-header">
                    <span>KafkaConsumer.java - 位移提交</span>
                    <span class="text-xs">Java</span>
                </div>
                <div class="code-content">
                    <pre><code>// KafkaConsumer.java
public void commitSync() {
    // 提交消费者位移，确保消息已经处理并可以标记为消费完毕
    synchronized (this) {
        commitOffsets();
    }
}</code></pre>
                </div>
            </div>
            
            <div class="grid md:grid-cols-2 gap-6">
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3">
                        enable.auto.commit
                    </h3>
                    <p class="text-gray-600">
                        决定消费者是否自动提交位移。如果设置为 true，Kafka 会在后台自动提交位移；如果设置为 false，消费者需要显式调用 commitSync 或 commitAsync 来提交位移。
                    </p>
                </div>
                
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3">
                        auto.commit.interval.ms
                    </h3>
                    <p class="text-gray-600">
                        如果启用了自动提交，则控制提交位移的时间间隔。较长的间隔可能增加消息重复消费的风险，而较短的间隔可能增加系统开销。
                    </p>
                </div>
            </div>
        </section>

        <div class="divider"></div>

        <!-- Broker Section -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold text-gray-800 mb-8">6. Kafka Broker 负载与磁盘 I/O</h2>
            <p class="text-gray-600 mb-6">
                Kafka Broker 在处理消费者的拉取请求时，依赖于磁盘的读取性能。如果 Broker 所在的机器磁盘 I/O 性能不足，可能导致消费者拉取消息的延迟。
            </p>
            
            <div class="code-block mb-6">
                <div class="code-header">
                    <span>FetchRequestHandler.java - Broker处理拉取请求</span>
                    <span class="text-xs">Java</span>
                </div>
                <div class="code-content">
                    <pre><code>// FetchRequestHandler.java
public void handleFetchRequest(FetchRequest fetchRequest) {
    // 从磁盘中读取数据
    FetchResponse fetchResponse = readFromDisk(fetchRequest);
}</code></pre>
                </div>
            </div>
            
            <div class="grid md:grid-cols-2 gap-6">
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3">
                        消息的存储
                    </h3>
                    <p class="text-gray-600">
                        Kafka 将消息存储在日志文件中，当消费者请求消息时，Broker 需要从这些文件中读取数据。如果磁盘性能差，可能导致延迟。
                    </p>
                </div>
                
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3">
                        副本同步
                    </h3>
                    <p class="text-gray-600">
                        如果 Kafka 集群的副本同步较慢，可能导致消费者拉取到的消息过期或不可用，增加消费延迟。
                    </p>
                </div>
            </div>
        </section>

        <div class="divider"></div>

        <!-- Monitoring Section -->
        <section id="solutions" class="mb-16">
            <h2 class="text-3xl font-bold text-gray-800 mb-8">7. Kafka 的消费延迟监控</h2>
            <p class="text-gray-600 mb-6">
                Kafka 提供了一些监控指标，用于跟踪消费者的消费延迟。这些指标可以帮助开发者及时发现消费延迟问题，并进行优化。
            </p>
            
            <div class="code-block mb-6">
                <div class="code-header">
                    <span>KafkaConsumer.java - 消费滞后监控</span>
                    <span class="text-xs">Java</span>
                </div>
                <div class="code-content">
                    <pre><code>// KafkaConsumer.java
public long getOffsetLag() {
    return offsetLag;
}</code></pre>
                </div>
            </div>
            
            <div class="grid md:grid-cols-2 gap-6">
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3">
                        消费滞后（Lag）
                    </h3>
                    <p class="text-gray-600">
                        offsetLag 用于表示消费者滞后的消息数量。高滞后意味着消费者消费的速度比生产者慢，可能导致延迟问题。
                    </p>
                </div>
                
                <div class="bg-white rounded-lg shadow-sm p-6 border border-gray-100">
                    <h3 class="text-lg font-semibold text-gray-800 mb-3">
                        延迟时间
                    </h3>
                    <p class="text-gray-600">
                        Kafka 提供了消费延迟的时间度量，可以通过 JMX 或 Prometheus 等工具进行监控。
                    </p>
                </div>
            </div>
            
            <div class="mt-10 bg-indigo-50 rounded-xl p-8">
                <h3 class="text-2xl font-bold text-indigo-800 mb-4 flex items-center">
                    <i class="fas fa-lightbulb mr-3"></i>
                    优化建议总结
                </h3>
                <ul class="text-indigo-700 space-y-3">
                    <li class="flex items-start">
                        <i class="fas fa-check-circle text-indigo-500 mr-2 mt-1"></i>
                        <span>合理配置消费者的拉取参数（fetch.min.bytes, fetch.max.wait.ms）</span>
                    </li>
                    <li class="flex items-start">
                        <i class="fas fa-check-circle text-indigo-500 mr-2 mt-1"></i>
                        <span>优化消费者的业务处理逻辑，减少处理时间</span>
                    </li>
                    <li class="flex items-start">
                        <i class="fas fa-check-circle text-indigo-500 mr-2 mt-1"></i>
                        <span>增加消费者实例数量或使用多线程处理</span>
                    </li>
                    <li class="flex items-start">
                        <i class="fas fa-check-circle text-indigo-500 mr-2 mt-1"></i>
                        <span>监控Broker的磁盘I/O性能，必要时升级硬件</span>
                    </li>
                    <li class="flex items-start">
                        <i class="fas fa-check-circle text-indigo-500 mr-2 mt-1"></i>
                        <span>设置合理的自动提交间隔或使用手动提交</span>
                    </li>
                    <li class="flex items-start">
                        <i class="fas fa-check-circle text-indigo-500 mr-2 mt-1"></i>
                        <span>持续监控消费滞后指标，建立告警机制</span>
                    </li>
                </ul>
            </div>
        </section>
    </main>

    <!-- Footer -->
    <footer class="bg-gray-900 text-gray-300 py-12">
        <div class="container mx-auto max-w-5xl px-4">
            <div class="flex flex-col md:flex-row justify-between items-center">
                <div class="mb-4 md:mb-0">
                    <h3 class="text-xl font-semibold text-white mb-2">技术小馆</h3>
                    <p class="text-gray-400">探索技术世界的每一个角落</p>
                </div>
                <div>
                    <a href="http://www.yuque.com/jtostring" class="text-indigo-300 hover:text-white transition duration-300 flex items-center">
                        <i class="fas fa-external-link-alt mr-2"></i>
                        http://www.yuque.com/jtostring
                    </a>
                </div>
            </div>
            <div class="border-t border-gray-800 mt-8 pt-8 text-center text-sm text-gray-500">
                &copy; 2023 技术小馆. 保留所有权利.
            </div>
        </div>
    </footer>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'dark',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
        
        // 简单的滚动动画
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                document.querySelector(this.getAttribute('href')).scrollIntoView({
                    behavior: 'smooth'
                });
            });
        });
    </script>
</body>
</html>
```